using Microsoft.Extensions.Logging;
using System.Collections.Concurrent;
using SumerCoreDevOps.Domain.Entities;
using SumerCoreDevOps.Infrastructure.Data;
using SumerCoreDevOps.Infrastructure.Distributed;
using SumerCoreDevOps.Infrastructure.Realtime;
using SumerCoreDevOps.Infrastructure.Tcp;
using SumerCoreDevOps.Infrastructure.Workflow;
using SumerCoreDevOps.Shared.Enums;
using SumerCoreDevOps.Shared.Models.Messages;
using TaskStatus = SumerCoreDevOps.Shared.Enums.TaskStatus;

namespace SumerCoreDevOps.Infrastructure.Scheduling;

/// <summary>
/// 任务调度器 (支持多主节点分布式任务分配)
/// </summary>
public class TaskScheduler
{
    private readonly FreeSQLProvider _dbProvider;
    private readonly NodeManager _nodeManager;
    private readonly WorkflowEngine _workflowEngine;
    private readonly TcpServer _tcpServer;
    private readonly ILogger<TaskScheduler> _logger;
    private readonly IRealtimeNotificationService? _realtimeService;
    private readonly IDistributedCoordinator? _coordinator;
    private readonly ConcurrentDictionary<long, TaskExecutionContext> _executingTasks = new();
    private readonly bool _useDistributedMode;

    public TaskScheduler(
        FreeSQLProvider dbProvider,
        NodeManager nodeManager,
        WorkflowEngine workflowEngine,
        TcpServer tcpServer,
        ILogger<TaskScheduler> logger,
        IRealtimeNotificationService? realtimeService = null,
        IDistributedCoordinator? coordinator = null)
    {
        _dbProvider = dbProvider;
        _nodeManager = nodeManager;
        _workflowEngine = workflowEngine;
        _tcpServer = tcpServer;
        _logger = logger;
        _realtimeService = realtimeService;
        _coordinator = coordinator;
        _useDistributedMode = coordinator != null;

        if (_useDistributedMode)
        {
            _logger.LogInformation("TaskScheduler启动在分布式模式，使用Redis协调");
        }
        else
        {
            _logger.LogInformation("TaskScheduler启动在单机模式");
        }

        // 注册工作流引擎的步骤下发事件
        _workflowEngine.OnStepDispatch += OnStepDispatchHandler;
    }

    /// <summary>
    /// 处理步骤下发
    /// </summary>
    private async Task OnStepDispatchHandler(WorkflowStepDispatchMessage message)
    {
        await ScheduleTaskAsync(message);
    }

    /// <summary>
    /// 调度任务
    /// </summary>
    public async Task ScheduleTaskAsync(WorkflowStepDispatchMessage message)
    {
        _logger.LogInformation("开始调度任务: TaskId={TaskId}, StepType={StepType}",
            message.TaskId, message.StepType);

        // 在分布式模式下，使用分布式锁避免重复分配
        if (_useDistributedMode && _coordinator != null)
        {
            await ScheduleTaskWithLockAsync(message);
        }
        else
        {
            await ScheduleTaskInternalAsync(message);
        }
    }

    /// <summary>
    /// 使用分布式锁调度任务
    /// </summary>
    private async Task ScheduleTaskWithLockAsync(WorkflowStepDispatchMessage message)
    {
        if (_coordinator == null) return;

        var lockKey = $"task:assign:{message.TaskId}";

        // 尝试获取分布式锁 (30秒超时)
        await using var distributedLock = await _coordinator.TryAcquireLockAsync(lockKey, TimeSpan.FromSeconds(30));

        if (distributedLock == null)
        {
            _logger.LogWarning("获取任务分配锁失败: TaskId={TaskId}, 可能已被其他主节点处理", message.TaskId);

            // 检查任务是否已被分配
            var task = await _dbProvider.Orm.Select<TaskEntity>()
                .Where(t => t.Id == message.TaskId)
                .FirstAsync();

            if (task?.Status == TaskStatus.Running)
            {
                _logger.LogInformation("任务已被其他主节点分配: TaskId={TaskId}", message.TaskId);
                return;
            }

            // 等待一段时间后重试
            await Task.Delay(1000);
            await using var retryLock = await _coordinator.TryAcquireLockAsync(lockKey, TimeSpan.FromSeconds(30));

            if (retryLock == null)
            {
                _logger.LogError("重试获取任务分配锁失败: TaskId={TaskId}", message.TaskId);
                await _workflowEngine.UpdateTaskStatusAsync(
                    message.TaskId,
                    TaskStatus.Failed,
                    0,
                    "无法获取任务分配锁，请稍后重试");
                return;
            }

            // 再次检查任务状态
            task = await _dbProvider.Orm.Select<TaskEntity>()
                .Where(t => t.Id == message.TaskId)
                .FirstAsync();

            if (task?.Status == TaskStatus.Running)
            {
                _logger.LogInformation("任务已被其他主节点分配（重试检查）: TaskId={TaskId}", message.TaskId);
                return;
            }
        }

        try
        {
            // 在锁保护下执行任务分配
            await ScheduleTaskInternalAsync(message);

            // 将任务上下文保存到Redis
            if (_executingTasks.TryGetValue(message.TaskId, out var context))
            {
                await _coordinator.SetAsync($"task:executing:{message.TaskId}", context, TimeSpan.FromHours(24));
            }
        }
        finally
        {
            // 锁会在 using 结束时自动释放
        }
    }

    /// <summary>
    /// 内部任务调度逻辑
    /// </summary>
    private async Task ScheduleTaskInternalAsync(WorkflowStepDispatchMessage message)
    {
        // 根据步骤类型确定所需环境
        string requiredEnvironment = DetermineRequiredEnvironment(message.StepType);

        // 选择合适的节点
        var node = await _nodeManager.SelectNodeForEnvironmentAsync(requiredEnvironment);

        if (node == null)
        {
            _logger.LogError("没有可用节点执行任务: TaskId={TaskId}, RequiredEnvironment={Environment}",
                message.TaskId, requiredEnvironment);

            await _workflowEngine.UpdateTaskStatusAsync(
                message.TaskId,
                TaskStatus.Failed,
                0,
                $"没有可用节点支持环境: {requiredEnvironment}");

            return;
        }

        // 更新任务记录
        await _dbProvider.Orm.Update<TaskEntity>()
            .Set(t => t.NodeId, node.Id)
            .Set(t => t.Status, TaskStatus.Running)
            .Set(t => t.StartTime, DateTime.UtcNow)
            .Where(t => t.Id == message.TaskId)
            .ExecuteAffrowsAsync();

        // 创建任务执行日志
        var task = await _dbProvider.Orm.Select<TaskEntity>()
            .Where(t => t.Id == message.TaskId)
            .FirstAsync();

        if (task != null)
        {
            // 获取步骤信息
            var step = await _dbProvider.Orm.Select<Step>()
                .Where(s => s.Id == task.StepId)
                .FirstAsync();

            // 获取阶段信息
            var stage = step != null ? await _dbProvider.Orm.Select<Stage>()
                .Where(s => s.Id == step.StageId)
                .FirstAsync() : null;

            // 获取工作流信息
            var workflow = stage != null ? await _dbProvider.Orm.Select<WorkflowDefinition>()
                .Where(w => w.Id == stage.WorkflowDefinitionId)
                .FirstAsync() : null;

            var executionLog = new TaskExecutionLog
            {
                TaskId = task.Id,
                PipelineInstanceId = task.PipelineInstanceId,
                WorkflowId = workflow?.Id ?? 0,
                WorkflowName = workflow?.Name ?? "Unknown",
                StageName = stage?.Name ?? "Unknown",
                StepName = step?.Name ?? "Unknown",
                StepType = message.StepType.ToString(),
                NodeId = node.Id,
                NodeName = node.NodeName,
                Status = TaskStatus.Running.ToString(),
                AssignedAt = DateTime.UtcNow,
                StartedAt = DateTime.UtcNow,
                Progress = 0,
                TaskConfig = message.StepConfig,
                CreatedAt = DateTime.UtcNow
            };

            await _dbProvider.Orm.Insert(executionLog).ExecuteAffrowsAsync();
            _logger.LogDebug("已创建任务执行日志: TaskId={TaskId}, LogId={LogId}", task.Id, executionLog.Id);
        }

        // 添加到执行中任务列表
        var context = new TaskExecutionContext
        {
            TaskId = message.TaskId,
            NodeId = node.Id,
            StartTime = DateTime.UtcNow
        };
        _executingTasks.TryAdd(message.TaskId, context);

        // 通过 TCP 下发任务到节点
        try
        {
            await _tcpServer.SendMessageAsync(
                node.Id,
                TcpMessageType.WorkflowStepDispatch,
                message);

            _logger.LogInformation("任务已下发到节点: TaskId={TaskId}, NodeId={NodeId}, NodeName={NodeName}",
                message.TaskId, node.Id, node.NodeName);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "任务下发失败: TaskId={TaskId}, NodeId={NodeId}",
                message.TaskId, node.Id);

            await _workflowEngine.UpdateTaskStatusAsync(
                message.TaskId,
                TaskStatus.Failed,
                0,
                $"任务下发失败: {ex.Message}");

            // 更新任务执行日志为失败
            await _dbProvider.Orm.Update<TaskExecutionLog>()
                .Set(log => log.Status, TaskStatus.Failed.ToString())
                .Set(log => log.ErrorMessage, $"任务下发失败: {ex.Message}")
                .Set(log => log.CompletedAt, DateTime.UtcNow)
                .Set(log => log.UpdatedAt, DateTime.UtcNow)
                .Where(log => log.TaskId == message.TaskId)
                .ExecuteAffrowsAsync();

            _executingTasks.TryRemove(message.TaskId, out _);
        }
    }

    /// <summary>
    /// 处理任务状态上报
    /// </summary>
    public async Task HandleTaskStatusReportAsync(long nodeId, StepStatusReportMessage message)
    {
        _logger.LogInformation("收到任务状态上报: TaskId={TaskId}, Status={Status}, Progress={Progress}",
            message.TaskId, message.Status, message.Progress);

        // 更新任务状态
        await _workflowEngine.UpdateTaskStatusAsync(
            message.TaskId,
            message.Status,
            message.Progress,
            message.ErrorMessage,
            message.OutputContext);

        // 获取任务信息以推送实时更新
        var task = await _dbProvider.Orm.Select<TaskEntity>()
            .Where(t => t.Id == message.TaskId)
            .FirstAsync();

        // 更新任务执行日志
        var isCompleted = message.Status == TaskStatus.Success ||
                          message.Status == TaskStatus.Failed ||
                          message.Status == TaskStatus.Cancelled;

        if (isCompleted)
        {
            // 任务完成，计算执行时长
            _executingTasks.TryRemove(message.TaskId, out var context);

            long? durationMs = null;
            if (context != null)
            {
                var duration = DateTime.UtcNow - context.StartTime;
                durationMs = (long)duration.TotalMilliseconds;
                _logger.LogInformation("任务完成: TaskId={TaskId}, Status={Status}, Duration={Duration}s",
                    message.TaskId, message.Status, duration.TotalSeconds);
            }

            // 更新执行日志（完成状态）
            var outputJson = message.OutputContext != null
                ? System.Text.Json.JsonSerializer.Serialize(message.OutputContext)
                : null;

            await _dbProvider.Orm.Update<TaskExecutionLog>()
                .Set(log => log.Status, message.Status.ToString())
                .Set(log => log.Progress, message.Progress)
                .Set(log => log.CompletedAt, DateTime.UtcNow)
                .Set(log => log.DurationMs, durationMs)
                .Set(log => log.ErrorMessage, message.ErrorMessage)
                .Set(log => log.TaskOutput, outputJson)
                .Set(log => log.UpdatedAt, DateTime.UtcNow)
                .Where(log => log.TaskId == message.TaskId)
                .ExecuteAffrowsAsync();
        }
        else
        {
            // 任务进行中，更新进度
            await _dbProvider.Orm.Update<TaskExecutionLog>()
                .Set(log => log.Status, message.Status.ToString())
                .Set(log => log.Progress, message.Progress)
                .Set(log => log.UpdatedAt, DateTime.UtcNow)
                .Where(log => log.TaskId == message.TaskId)
                .ExecuteAffrowsAsync();
        }

        // 推送实时状态更新到前端
        if (_realtimeService != null && task != null)
        {
            await _realtimeService.PushTaskStatusAsync(
                message.TaskId,
                task.PipelineInstanceId,
                message.Status.ToString(),
                message.Progress,
                message.ErrorMessage);
        }
    }

    /// <summary>
    /// 处理日志流
    /// </summary>
    public async Task HandleLogStreamAsync(long nodeId, LogStreamMessage message)
    {
        _logger.LogDebug("收到日志流: TaskId={TaskId}, LogLevel={LogLevel}, Content={Content}",
            message.TaskId, message.LogLevel, message.LogContent);

        try
        {
            // 将日志写入文件系统
            if (!string.IsNullOrEmpty(message.LogContent))
            {
                // 构建日志目录和文件路径
                var logDirectory = Path.Combine("/var/log/sumer-devops", "tasks");
                var logFilePath = Path.Combine(logDirectory, $"task-{message.TaskId}.log");

                // 确保日志目录存在
                if (!Directory.Exists(logDirectory))
                {
                    Directory.CreateDirectory(logDirectory);
                }

                // 追加日志内容到文件
                var logEntry = $"[{DateTime.UtcNow:yyyy-MM-dd HH:mm:ss.fff}] [{message.LogLevel}] {message.LogContent}{Environment.NewLine}";
                await File.AppendAllTextAsync(logFilePath, logEntry);

                // 更新数据库中的日志路径（仅第一次写入时）
                await _dbProvider.Orm.Update<TaskEntity>()
                    .Set(t => t.LogPath, logFilePath)
                    .Where(t => t.Id == message.TaskId && (t.LogPath == null || t.LogPath == ""))
                    .ExecuteAffrowsAsync();

                _logger.LogTrace("日志已写入: {LogPath}", logFilePath);

                // 推送实时日志到前端
                if (_realtimeService != null)
                {
                    // 获取任务的流水线实例ID
                    var task = await _dbProvider.Orm.Select<TaskEntity>()
                        .Where(t => t.Id == message.TaskId)
                        .FirstAsync();

                    if (task != null)
                    {
                        await _realtimeService.PushTaskLogAsync(
                            message.TaskId,
                            task.PipelineInstanceId,
                            message.LogLevel,
                            message.LogContent);
                    }
                }
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "处理日志流失败: TaskId={TaskId}", message.TaskId);
        }
    }

    /// <summary>
    /// 处理清理结果
    /// </summary>
    public async Task HandleCleanupResultAsync(long nodeId, CleanupResultMessage message)
    {
        _logger.LogInformation("收到清理结果: TaskId={TaskId}, Success={Success}, FreedSpace={FreedSpace}MB",
            message.TaskId, message.Success, message.FreedSpaceMB);

        if (!message.Success)
        {
            _logger.LogWarning("清理失败: TaskId={TaskId}, Error={Error}, RemainingFiles={RemainingFiles}",
                message.TaskId, message.ErrorMessage, message.RemainingFiles.Count);
        }

        await Task.CompletedTask;
    }

    /// <summary>
    /// 获取正在执行的任务列表
    /// </summary>
    public List<TaskExecutionContext> GetExecutingTasks()
    {
        return _executingTasks.Values.ToList();
    }

    /// <summary>
    /// 确定所需环境
    /// </summary>
    private string DetermineRequiredEnvironment(StepType stepType)
    {
        return stepType switch
        {
            StepType.GitClone => "git",
            StepType.Build => "build",
            StepType.Test => "test",
            StepType.DeployDocker => "docker",
            StepType.DeployK8s => "kubernetes",
            StepType.UploadMaven => "maven",
            StepType.UploadNuGet => "nuget",
            _ => "general"
        };
    }
}

/// <summary>
/// 任务执行上下文
/// </summary>
public class TaskExecutionContext
{
    public long TaskId { get; set; }
    public long NodeId { get; set; }
    public DateTime StartTime { get; set; }
}
